package tempEngine.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import tempEngine.network.protocols.exceptions.CommunicationException;

public abstract class SocketThread extends Thread {
	/* *********************************************************
	 * Attributes
	 * ********************************************************* */
	public static final int VERSION = 1;
	private Socket _sock;
	protected BufferedReader _in;
	protected PrintWriter _out;
	private boolean _running;
	
	/* *********************************************************
	 * Constructor(s)
	 * ********************************************************* */
	/**
	 * basic constructor
	 * @param s Socket designed to be used by the thread 
	 */
	public SocketThread(Socket s) throws UnknownHostException, IOException{
		_sock = s;
		_in = new BufferedReader(
				new InputStreamReader(_sock.getInputStream()));
		_out = new PrintWriter(_sock.getOutputStream());
		_running = true;
	}
	
	/**
	 * @see Thread
	 * 
	 * NOTE : this implementation of run is a Template Method 
	 * (see Design Pattern GoF's Book)
	 */
	@Override
	public void run() {
		super.run();
		
		try{
			if(this.versionChecking()){	
				this.preRunLoopHandling();
				
				while (_running) { // <--- here is the runLoop !
					this.runLoopHandling();
				}
				this.postRunLoopHandling();
			}else{
				System.out.println("communication over due to incorrect " +
				"version numbers");
		
			}
		}catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (CommunicationException e) {
			e.printStackTrace();
		}
	}
	
	

	/**
	 * method called every runLoop iteration
	 */
	protected abstract void runLoopHandling();
	/**
	 * method called before the runLoop
	 * @throws IOException throws if experiencing problems reading or
	 *  writing on the socket
	 * @throws CommunicationExceptionException throws if experiencing 
	 * a problem following the supposed communication protocol. 
	 */
	protected abstract void preRunLoopHandling() throws  IOException, CommunicationException;
	
	/**
	 * method called after the runLoop
	 */
	protected abstract void postRunLoopHandling();
	
	
	/**
	 * set if the runLoop should stop or not
	 * @param running
	 */
	public void setRunning(boolean running){
		_running = running;
	}
	
	/**
	 * check if the given version number is compatible with ours 
	 *  version
	 * @return true if no problems should be experienced during the 
	 *  communication
	 * @throws IOException throws if experiencing problems reading or
	 *  writing on the socket
	 * @throws NumberFormatException throws if experiencing problems 
	 *  parsing line that should be number during the dialog.
	 */
	protected boolean versionChecking() throws NumberFormatException, IOException {
		//send the version number first and flush
		_out.println(SocketThread.VERSION);
		_out.flush();
		//then read the version :
		int distantVersion = Integer.parseInt(_in.readLine());
		return distantVersion == SocketThread.VERSION;
	}
}
